<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
    <!-- 百度禁止转码 -->
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <!-- uc强制竖屏 -->
    <meta name="screen-orientation" content="portrait" />
    <!-- QQ强制竖屏 -->
    <meta name="x5-orientation" content="portrai" />
    <!-- 禁用电话号码邮箱自动识别 -->
    <meta name="format-detection" content="telephone=no,email=no" />
    <title>document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      html,
      body {
        height: 100%;
      }

      .wrap {
        background-color: #111;
        height: calc(100% - 100px);
        position: relative;
      }

      .star {
        width: 10vw;
        height: 10vw;
        background: url(./images/star.gif) no-repeat center;
        background-size: contain;
        position: absolute;
        transition: all 1s ease;
        left: 0;
        top: 0;
        /* z-index: 1000; */
        /* will-change: transform; */
        /* transform: translateZ(0px); */
      }

      button {
        appearance: none;
        padding: 3px;
        margin-top: 4px;
      }

      .dib {
        display: inline-block;
        margin-left: 20px;
      }

      .btn_wrap {
        height: 100px;
        position: relative;
        padding-right: 60px;
      }

      #fps {
        position: absolute;
        right: 10px;
        top: 10px;
        color: rgba(70, 270, 40, 0.8);
      }

      #starCount {
        position: absolute;
        right: 10px;
        top: 40px;
        color: rgba(270, 70, 40, 0.8);
        z-index: 50;
        transform: translateZ(0px);
      }
    </style>
  </head>

  <body>
    <div class="btn_wrap">
      <button onclick="addStar(10, event)">添加10星星</button>
      <button onclick="addStar(100, event)">添加100星星</button>
      <button id="domHandler">dom操作优化on</button>
      <div id="starCount">星星数目: 10</div>
      <div id="fps">FPS: 60</div>
      <button class="dib" id="dibAlert">帧率提示</button>
      <button id="switchParLayer">父元素合成层on</button>
      <button id="switchFrame">动画帧on</button>
      <button id="switchChiLayer">子元素独立帧on</button>
      <a href="星星移动动画canvas.html">高性能版</a>
    </div>
    <div class="wrap" id="starWrap">
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
      <div class="star"></div>
    </div>
    <script>
      var starCount = 10,
        starWrap = document.getElementById('starWrap'),
        clientWidth = starWrap.clientWidth,
        clientHeight = starWrap.clientHeight,
        maxLeft = clientWidth * 0.85,
        maxTop = clientHeight - clientWidth * 0.1,
        timer,
        isCountChange = true,
        starArr,
        starCountWrap = document.getElementById('starCount'),
        fpsWrap = document.getElementById('fps'),
        // 帧率计算
        frame = 0,
        allFrameCount = 0,
        lastTime = Date.now(),
        lastFameTime = Date.now(),
        now,
        fs,
        // 是否性能优化开启
        switchDomHandler = false,
        // 父元素是否开启合成层
        switchParLayer = false,
        // 动画帧调用是否开启
        switchFrame = false,
        // 子元素独立帧是否开启
        switchChiLayer = false
      function rAF(callback) {
        window.requestAnimationFrame(callback) || window.webkitRequestAnimationFrame(callback) || window.mozRequestAnimationFrame(callback) || window.setTimeout(callback, 1000 / 60)
      }
      function loop() {
        ;(now = Date.now()), (fs = now - lastFameTime), (fps = Math.round(1000 / fs))
        lastFameTime = now
        // 不置 0，在动画的开头及结尾记录此值的差值算出 FPS
        allFrameCount++
        frame++

        if (now > 1000 + lastTime) {
          var fps = Math.round((frame * 1000) / (now - lastTime))
          fpsWrap.innerHTML = `FPS: ${fps}`
          frame = 0
          lastTime = now
        }

        rAF(loop)
      }

      function ready(fn) {
        if (document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading') {
          fn()
        } else {
          document.addEventListener('DOMContentLoaded', fn)
        }
      }

      function randomLeft() {
        if (!switchDomHandler) return Math.floor(Math.random() * (clientWidth - 50) * 0.85)
        return Math.floor(Math.random() * maxLeft)
      }
      function randowTop() {
        if (!switchDomHandler) return Math.floor(Math.random() * (clientHeight - 150) * 0.85)
        return Math.floor(Math.random() * maxTop)
      }
      // 创建下一次的位置
      function makeCssText() {
        if (switchChiLayer) return `transform: translate(${randomLeft()}px, ${randowTop()}px);`
        return `left: ${randomLeft()}px; top: ${randowTop()}px;`
      }
      function animation() {
        if (!switchDomHandler) {
          starArr = document.querySelectorAll('.star')
        } else {
          if (isCountChange) {
            starArr = starWrap.querySelectorAll('.star')
            isCountChange = false
          }
        }
        for (let index = 0; index < starCount; index++) {
          starArr[index].style.cssText = makeCssText()
        }
      }

      function intervalTask() {
        function callBack() {
          animation()
          timer && clearTimeout(timer)
          timer = setTimeout(intervalTask, 1300)
        }
        if (switchFrame) {
          rAF(callBack)
          return
        }
        callBack()
      }

      function addStar(number, e) {
        e.preventDefault()
        timer && clearTimeout(timer)
        starCount += number
        if (switchDomHandler) {
          isCountChange = true
          var flagMent = document.createDocumentFragment(),
            el = document.createElement('div')
          el.className = 'star'
          for (let index = 0; index < number; index++) {
            let cloneEl = el.cloneNode(true)
            cloneEl.style.cssText = makeCssText()
            flagMent.appendChild(cloneEl)
          }
          starWrap.appendChild(flagMent)
        } else {
          for (let index = 0; index < number; index++) {
            var el = document.createElement('div')
            el.className = 'star'
            el.style.cssText = makeCssText()
            document.getElementById('starWrap').appendChild(el)
          }
        }
        document.getElementById('starCount').innerHTML = `星星数目: ${starCount}`
        intervalTask()
      }

      ready(() => {
        // 初始化
        animation()
        timer = setTimeout(intervalTask, 1300)
        loop()
        document.getElementById('dibAlert').addEventListener(
          'click',
          e => {
            e.preventDefault()
            alert(
              '帧率能够达到 50 ～ 60 FPS 的动画将会相当流畅，让人倍感舒适；帧率在 30 ～ 50 FPS 之间的动画，因各人敏感程度不同，舒适度因人而异；帧率在 30 FPS 以下的动画，让人感觉到明显的卡顿和不适感；帧率波动很大的动画，亦会使人感觉到卡顿。'
            )
          },
          false
        )
        document.getElementById('domHandler').addEventListener(
          'click',
          function(e) {
            e.preventDefault()
            switchDomHandler = !switchDomHandler
            if (switchDomHandler) {
              fpsWrap.style.cssText = `z-index: 50;transform: translateZ(0px);`
              this.innerHTML = 'dom操作优化off'
              return
            }
            fpsWrap.style.cssText = ''
            this.innerHTML = 'dom操作优化on'
          },
          false
        )
        document.getElementById('switchParLayer').addEventListener(
          'click',
          function(e) {
            e.preventDefault()
            switchParLayer = !switchParLayer
            if (switchParLayer) {
              starWrap.style.cssText = `z-index: 90;transform: translateZ(0px);will-change: left;`
              this.innerHTML = '父元素合成层off'
              return
            }
            starWrap.style.cssText = ''
            this.innerHTML = '父元素合成层on'
          },
          false
        )
        document.getElementById('switchFrame').addEventListener(
          'click',
          function(e) {
            e.preventDefault()
            switchFrame = !switchFrame
            if (switchFrame) {
              starWrap.style.cssText = `z-index: 90;transform: translateZ(0px);will-change: left;`
              this.innerHTML = '动画帧off'
              return
            }
            starWrap.style.cssText = ''
            this.innerHTML = '动画帧on'
          },
          false
        )
        document.getElementById('switchChiLayer').addEventListener(
          'click',
          function(e) {
            e.preventDefault()
            switchChiLayer = !switchChiLayer
            if (switchChiLayer) {
              this.innerHTML = '子元素独立帧off'
              return
            }
            this.innerHTML = '子元素独立帧on'
          },
          false
        )
        window.addEventListener(
          'resize',
          () => {
            clientWidth = starWrap.clientWidth
            clientHeight = starWrap.clientHeight
            maxLeft = clientWidth * 0.85
            maxTop = clientHeight - clientWidth * 0.1
          },
          false
        )
      }, false)
    </script>
  </body>
</html>
